package gis.lifay.sdk;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RuntimeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 *@ClassName TileSdk
 *@Description 切片SDK类
 *@Author lifay
 *@Date 2021/11/1 11:30
 **/
public class TileSdk {

    private static Logger log = LoggerFactory.getLogger(TileSdk.class);

    private static final String TILE_SDK_DLL = System.getProperty("user.dir") + File.separator + "dll" + File.separator + "tile.exe";

    public static class ExecBody {
        private int code;
        private String msg;
        private float time;

        public float getTime() {
            return time;
        }

        public void setTime(float time) {
            this.time = time;
        }

        public int getCode() {
            return code;
        }

        public void setCode(int code) {
            this.code = code;
        }

        public String getMsg() {
            return msg;
        }

        public void setMsg(String msg) {
            this.msg = msg;
        }
    }

    public static void checkSdk() {
        Assert.isTrue(FileUtil.exist(TILE_SDK_DLL));
    }

    /**
     * 切片
     * @param tileModel
     * @return
     * @throws Exception
     */
    public static ExecBody process(TileModel tileModel) throws Exception {
        //检查sdk文件
        checkSdk();
        //检查输入参数
        Assert.notBlank(tileModel.getId());
        Assert.notBlank(tileModel.getTitle());
        Assert.notBlank(tileModel.getProfile());
        Assert.notBlank(tileModel.getZoom());
        Assert.notBlank(tileModel.getInputFile());
        Assert.notBlank(tileModel.getOutPath());
        //检查文件
        if (!FileUtil.exist(tileModel.getInputFile())) {
            throw new FileNotFoundException("file not find :" + tileModel.getInputFile());
        }
        //组装参数
        String cmd = build(tileModel);
        //获取临时日志文件
        String tempLogPath = getLogPath(tileModel.getId());
        //执行
        long s = System.currentTimeMillis();
        ExecBody execBody = exec(cmd, tempLogPath);
        long e = System.currentTimeMillis();
        execBody.setTime((float) (e - s) / 1000);
        return execBody;
    }

    public static String getLogPath(String id) {
        return System.getProperty("user.dir") + File.separator + "logs" + File.separator + id + ".log";
    }

    /**
     * 组装参数
     * @param tileModel
     * tile.exe --no-kml -p raster --zoom=0-6 -nb_processes=2 D:\IdeaProjects\TestHDFInstal\H4GRImage_bytesNature.jpg F:\\OutFile\\test_band-exe1-jpg
     * @return
     */
    private static String build(TileModel tileModel) {
        StringBuffer sb = new StringBuffer(TILE_SDK_DLL);
        sb.append(" ");
        if (tileModel.isNoKml()) {
            sb.append("--no-kml ");
        }
        sb.append("-p ").append(tileModel.getProfile()).append(" ");

        sb.append("--zoom=").append(tileModel.getZoom()).append(" ");

        sb.append("-nb_processes=").append(tileModel.getProcesses()).append(" ");

        sb.append(tileModel.getInputFile()).append(" ");

        sb.append(tileModel.getOutPath()).append(" ");

        return sb.toString();
    }

    /**
     * 执行命令
     * @param cmd
     * @param logPath
     * @return
     */
    public static ExecBody exec(String cmd, String logPath) {
        log.info("cmd >> " + cmd);
        ExecBody execBody = new ExecBody();
        Process process = RuntimeUtil.exec(cmd);
        InputStream inputStream = null;
        StringBuilder lines = new StringBuilder();
        try {
            inputStream = process.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                logToLocal(logPath, false, line);
                lines.append(line);
            }
            process.waitFor();
            if (process.exitValue() != 0) {
                logToLocal(logPath, true, " 脚本异常:" + process.exitValue() + " >> " + lines);
                throw new RuntimeException(" 脚本异常:" + process.exitValue() + " >> " + lines);
            }
            logToLocal(logPath, false, "执行状态:{}" + process.exitValue());
        } catch (Exception e) {
            e.printStackTrace();
            logToLocal(logPath, true, "命令[{}]执行失败:{}" + cmd + e.getMessage());
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                execBody.setCode(process.exitValue());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        execBody.setMsg(lines.toString());
        return execBody;
    }

    /**
     * 将输出内容写入本地日志文件
     * @param logPath
     * @param line
     */
    private static synchronized void logToLocal(String logPath, boolean error, String line) {
        FileUtil.writeString(line + "\n", new File(logPath), StandardCharsets.UTF_8);
        if (error) {
            log.error(line);
        } else {
            log.info(line);
        }
    }

    /**
     * 生成缩略图
     * @param src
     * @param dst
     * @param ext
     * @param w
     * @param h
     * @throws IOException
     */
    public static void toShrotImg(String src, String dst, String ext, int w, int h) throws IOException {
        BufferedImage bis = ImageIO.read(new File(src));
        BufferedImage bid = new BufferedImage(w, h, 1);
        Graphics2D g = bid.createGraphics();
        //将读取原文件 写在目标文件的 0,0  w h 范围
        g.drawImage(bis, 0, 0, w, h, null);
        FileOutputStream fileOutputStream = new FileOutputStream(dst);
        ImageIO.write(bid, ext, fileOutputStream);
        g.dispose();
        fileOutputStream.close();
    }

}
